import tkinter as tk
from tkinter import filedialog, messagebox, PhotoImage
import requests
import os
import re
import logging
from PIL import Image, ImageTk

# 服务器地址
SERVER_URL = 'http://127.0.0.1:5000'


def is_valid_date(date):
    """
    验证日期格式是否为 YYYY-MM-DD
    """
    pattern = r'^\d{4}-\d{2}-\d{2}$'
    if not bool(re.match(pattern, date)):
        messagebox.showerror("错误", f"日期格式错误，应输入 YYYY-MM-DD 格式，你输入的是: {date}")
    return bool(re.match(pattern, date))


def upload_invoice():
    """
    选择发票文件并上传到服务器
    """
    file_path = filedialog.askopenfilename()
    if file_path:
        with open(file_path, 'rb') as f:
            files = {'file': f}
            response = requests.post(f'{SERVER_URL}/upload', files=files)
            try:
                if response.status_code == 200:
                    result = response.json()
                    messagebox.showinfo("发票识别结果", str(result))
                else:
                    error_info = response.json().get('error')
                    if error_info:
                        messagebox.showerror("错误", error_info)
                    else:
                        messagebox.showerror("错误", f"服务器返回错误状态码: {response.status_code}")
            except requests.exceptions.JSONDecodeError:
                error_text = response.text
                if "Traceback" in error_text:
                    # 提取服务器端的错误信息
                    start_index = error_text.find("Traceback")
                    error_text = error_text[start_index:].strip()
                messagebox.showerror("错误", f"服务器返回非JSON格式响应: {error_text}")


def query_invoices():
    start_date = start_date_entry.get()
    end_date = end_date_entry.get()
    keyword = keyword_entry.get()
    if start_date and not is_valid_date(start_date):
        messagebox.showerror("错误", "开始日期格式必须为YYYY-MM-DD")
        return
    if end_date and not is_valid_date(end_date):
        messagebox.showerror("错误", "结束日期格式必须为YYYY-MM-DD")
        return
    params = {}
    if start_date:
        params['start_date'] = start_date
    if end_date:
        params['end_date'] = end_date
    if keyword:
        params['keyword'] = keyword
    try:
        response = requests.get(f'{SERVER_URL}/query', params=params)
        if response.status_code == 200:
            results = response.json()
            if not results:
                messagebox.showinfo("提示", "未找到符合条件的发票")
            else:
                invoice_listbox.delete(0, tk.END)
                for result in results:
                    img_path = result['image_path']
                    if img_path is None:
                        logging.warning("图片路径为空，无法显示图片")
                        continue
                    img_path = re.sub(r'^.*?(?=\w:\S*$)', '', img_path).strip()
                    if not img_path:
                        logging.warning("图片路径为空或无效，无法显示图片")
                        continue
                    base_dir = os.path.dirname(os.path.abspath(__file__))
                    full_img_path = os.path.join(base_dir, img_path) if not os.path.isabs(img_path) else img_path
                    if not os.path.exists(full_img_path):
                        logging.warning(f"图片路径不存在: {full_img_path}")
                        continue
                    if not os.access(full_img_path, os.R_OK):
                        logging.warning(f"没有权限访问图片: {full_img_path}")
                        continue
                    invoice_number = result.get('invoice_number', '未知')
                    invoice_date = result.get('invoice_date', '未知')
                    invoice_code = result.get('invoice_code', '未知')
                    invoice_type = result.get('invoice_type', '未知')
                    commodity_name = result.get('commodity_name', '未知')
                    display_text = f"日期: {invoice_date}, 代码: {invoice_code}, 号码: {invoice_number}, 类型: {invoice_type}, 货物或应税劳务、服务名称: {commodity_name}"
                    index = invoice_listbox.size()
                    invoice_listbox.insert(tk.END, display_text)

                def show_selected_image(event):
                    selected_index = invoice_listbox.curselection()
                    if selected_index:
                        index = selected_index[0]
                        result = results[index]
                        img_path = result['image_path']
                        if img_path is None:
                            logging.warning("图片路径为空，无法显示图片")
                            return
                        img_path = re.sub(r'^.*?(?=\w:\S*$)', '', img_path).strip()
                        if not img_path:
                            logging.warning("图片路径为空或无效，无法显示图片")
                            return
                        base_dir = os.path.dirname(os.path.abspath(__file__))
                        full_img_path = os.path.join(base_dir, img_path) if not os.path.isabs(img_path) else img_path
                        if not os.path.exists(full_img_path):
                            logging.warning(f"图片路径不存在: {full_img_path}")
                            return
                        if not os.access(full_img_path, os.R_OK):
                            logging.warning(f"没有权限访问图片: {full_img_path}")
                            return
                        show_invoice_image(full_img_path)

                invoice_listbox.bind("<<ListboxSelect>>", show_selected_image)
        else:
            error_info = response.json().get('error')
            if error_info:
                messagebox.showerror("错误", error_info)
            else:
                messagebox.showerror("错误", f"服务器返回错误状态码: {response.status_code}")
    except requests.exceptions.JSONDecodeError:
        error_text = response.text
        if "Traceback" in error_text:
            start_index = error_text.find("Traceback")
            error_text = error_text[start_index:].strip()
        messagebox.showerror("错误", f"服务器返回非JSON格式响应: {error_text}")
    except requests.RequestException as e:
        messagebox.showerror("错误", f"请求服务器时出现错误: {e}")


def show_invoice_image(image_path):
    try:
        img = Image.open(image_path)
        max_width = 800
        max_height = 600
        width, height = img.size
        if width > max_width or height > max_height:
            ratio = min(max_width / width, max_height / height)
            new_width = int(width * ratio)
            new_height = int(height * ratio)
            img = img.resize((new_width, new_height), Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.ANTIALIAS)
        img = ImageTk.PhotoImage(img)
        # 创建一个新窗口来显示图片
        image_window = tk.Toplevel(root)
        image_window.title("发票图片")
        # 创建一个Canvas用于显示图片，并添加滚动条
        canvas = tk.Canvas(image_window, width=max_width, height=max_height)
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        # 创建垂直和水平滚动条
        vscrollbar = tk.Scrollbar(image_window, orient=tk.VERTICAL, command=canvas.yview)
        vscrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        hscrollbar = tk.Scrollbar(image_window, orient=tk.HORIZONTAL, command=canvas.xview)
        hscrollbar.pack(side=tk.BOTTOM, fill=tk.X)
        canvas.configure(yscrollcommand=vscrollbar.set, xscrollcommand=hscrollbar.set)
        canvas.create_image(0, 0, image=img, anchor=tk.NW)
        canvas.image = img
        canvas.config(scrollregion=canvas.bbox(tk.ALL))
    except FileNotFoundError:
        messagebox.showerror("错误", "发票图片不存在")
    except ImportError:
        messagebox.showerror("错误", "缺少PIL库，请安装后再尝试")
    except Exception as e:
        messagebox.showerror("错误", f"显示图片时出现错误: {str(e)}")


def statistics_invoices():
    start_date = start_date_entry.get()
    end_date = end_date_entry.get()
    keyword = keyword_entry.get()
    if start_date and not is_valid_date(start_date):
        messagebox.showerror("错误", "开始日期格式必须为YYYY-MM-DD")
        return
    if end_date and not is_valid_date(end_date):
        messagebox.showerror("错误", "结束日期格式必须为YYYY-MM-DD")
        return
    params = {}
    if start_date:
        params['start_date'] = start_date
    if end_date:
        params['end_date'] = end_date
    if keyword:
        params['keyword'] = keyword
    try:
        response = requests.get(f'{SERVER_URL}/statistics', params=params)
        if response.status_code == 200:
            stats = response.json()
            invoice_count = stats.get('invoice_count', '未知')
            total_amount = stats.get('total_amount', '未知')
            # 增加单位“元”
            if total_amount != '未知':
                total_amount = f"{total_amount} 元"
            messagebox.showinfo("发票统计信息", f"指定日期范围内的发票数量为: {invoice_count}, 总金额为: {total_amount}")
        else:
            error_info = response.json().get('error')
            if error_info:
                messagebox.showerror("错误", error_info)
            else:
                messagebox.showerror("错误", f"服务器返回错误状态码: {response.status_code}")
    except requests.exceptions.JSONDecodeError:
        messagebox.showerror("错误", f"服务器返回非JSON格式响应: {response.text}")
    except requests.RequestException as e:
        messagebox.showerror("错误", f"请求服务器时出现错误: {e}")


# 创建主窗口
root = tk.Tk()
root.title("智能发票管理系统")
# 上传按钮
upload_button = tk.Button(root, text="上传发票", command=upload_invoice)
upload_button.pack(pady=10)
# 查询输入框
start_date_label = tk.Label(root, text="开始日期 (YYYY-MM-DD):")
start_date_label.pack()
start_date_entry = tk.Entry(root)
start_date_entry.pack()
end_date_label = tk.Label(root, text="结束日期 (YYYY-MM-DD):")
end_date_label.pack()
end_date_entry = tk.Entry(root)
end_date_entry.pack()
keyword_label = tk.Label(root, text="关键字:")
keyword_label.pack()
keyword_entry = tk.Entry(root)
keyword_entry.pack()
# 查询按钮
query_button = tk.Button(root, text="查询发票", command=query_invoices)
query_button.pack(pady=10)
# 统计按钮
statistics_button = tk.Button(root, text="统计发票", command=statistics_invoices)
statistics_button.pack(pady=10)
# 发票列表框
invoice_listbox = tk.Listbox(root, width=80)
invoice_listbox.pack(pady=10)
# 运行主循环
root.mainloop()